package cis.view;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;

import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 * AbstractPieChart.java
 * 
 * Project #5
 * CS 2334 Programming Structure and Abstractions
 * May 1, 2011
 * 
 * <p>
 * This class contains the basic definitions for a PieChart to be rendered.  It
 * defines the colors that will be used, the bounded area for this chart and 
 * the container the holds these bounds as well as the actions performed on this
 * view component.
 * </p>
 *
 * @version 1.0
 */
public abstract class AbstractPieChart extends JPanel implements ActionListener 
                                                                               {
	/** Eclipse generated serial version ID. */
	private static final long serialVersionUID = 1601926410500952920L;
	/** The frame that will contain the pie chart. */
	private JFrame frame = new JFrame();
	/** A list of colors that will be used by the pie charts. */
	protected ArrayList<Slice> slices = new ArrayList<Slice>();
	/** The y offset value for rendering a key. */
	private int y_offset = 30;
	/** The x offset value for rendering a key. */
	private int x_offset = 420;
	
	/**
	 * <p>
	 * Default constructor for this class.
	 * </p>
	 * 
	 * <dt><b>Conditions:</b>
	 * <dd>PRE:  None</dd>
	 * <dd>POST: None</dd>
	 * </dt>	
	 */
	public AbstractPieChart() {
		this.frame.setBounds(
				(Toolkit.getDefaultToolkit().getScreenSize().width / 2) - 500, 
				(Toolkit.getDefaultToolkit().getScreenSize().height / 2) - 300, 
				1000, 600);
		this.frame.add(this);
		this.frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
		this.frame.setResizable(false);
	}	// end constructor
	
	/**
	 * <p>
	 * Generates the colors that will be used to graph different slices in the 
	 * pie chart.  This method uses recursion to obtain the list.
	 * </p>
	 * 
	 * @return A new randomly generated color.
	 * 
	 * <dt><b>Conditions:</b>
	 * <dd>PRE:  <code>colors</code> must be defined and hold a value.</dd>
	 * <dd>POST: <code>colors</code> is populated with a list of colors.</dd>
	 * </dt>
	 */
	public Color generateColor() {
		// Random number generator
		Random randomNumber = new Random();
		
		// Randomly pick RGB colors.
		int red   = randomNumber.nextInt(255);
		int green = randomNumber.nextInt(255);
		int blue  = randomNumber.nextInt(255);
		
		return new Color(red, green, blue);
	}	// end method
	
	/** 
	 * <p>
	 * Acquires the frame element for this view.
	 * </p>
	 * 
	 * @return The frame associated with this view component.
	 * 
	 * <dt><b>Conditions:</b>
	 * <dd>PRE:  <code>frame</code> must be assigned and contain a value.</dd>
	 * <dd>POST: The value held by <code>frame</code> is returned to the 
	 *           requester.</dd>
	 * </dt>
	 */
	public JFrame getFrame() {
		return this.frame;
	}	// end method

	/**
	 * <p>
	 * Draws a slice for the pie chart with the designated color and size.
	 * </p>
	 * 
	 * @param g The Graphics renderer for this panel.
	 * @param c The color of the slice to render
	 * @param start	The starting angle for this slice.
	 * @param end The ending angle for this slice.
	 * 
	 * <dt><b>Conditions:</b>
	 * <dd>PRE:  The size of the pie will be calculated from the length of the 
	 *           households that are available for the chart.</dd>
	 * <dd>POST: The slice is rendered to the panel.</dd>
	 * </dt>
	 */
	public void drawSlice(Graphics g, Slice slice) {
		// Set the color to the color desired.
		g.setColor(slice.getColor());
		// Draw the slice to the panel.
		g.fillArc(10, 75, 400, 400, 
				(int)slice.getStartAngle()-Math.round(slice.getAngle()), 
				(int)slice.getAngle());
		// Reset the color to default value
		g.setColor(Color.BLACK);
	}	// end method
	
	/**
	 * <p>
	 * Paints the pie chart to the panel.
	 * </p>
	 *          
	 * <dt><b>Conditions:</b>
	 * <dd>PRE:  <code>place</code> must be assigned a value.</dd>
	 * <dd>POST: The chart is constructed from data contained within 
	 *           <code>place</code>.</dd>
	 * </dt>
	 */
	public void drawChart(Graphics g) {
		// Make sure key offsets start at default values.
		this.x_offset = 420;
		this.y_offset = 30;
		
		// Recompile the slices
		this.getSlices();
		// Iterator for cycling all slices
		Iterator<Slice> sliceIterator = this.slices.iterator();
		
		// Cycle all slices for rendering
		while(sliceIterator.hasNext()) {
			Slice toRender = sliceIterator.next();
			this.drawSlice(g, toRender);
			this.drawKey(g, toRender);
		}	// end while
	}	// end method
	
	/**
	 * <p>
	 * Paints the key for each pie slice to the panel.
	 * </p>
	 * 
	 * @param g The Graphics class that contains the functions to paint to this 
	 *          panel.
	 *          
	 * <dt><b>Conditions:</b>
	 * <dd>PRE:  <code>place</code> must be assigned a value.</dd>
	 * <dd>POST: The key is constructed from data contained within 
	 *           <code>place</code>.</dd>
	 * </dt>
	 */
	public void drawKey(Graphics g, Slice toRender) {
		// Acquire the color representation for this key
		g.setColor(toRender.getColor());
		// Draw a square denoting this color
		g.fillRect(x_offset , y_offset, 10, 10);
		// Set color for border
		g.setColor(Color.BLACK);
		// Draw the border square
		g.drawRect(x_offset, y_offset, 11, 11);
		// Draw the key string
		g.drawString(toRender.getKeyString(), x_offset+15, y_offset+10);
		// Recalculate offsets
		if(y_offset < 540) {
			y_offset += 30;
		} else {
			y_offset = 30;
			x_offset += 180;
		}	// end if
	}	// end method
	
	/**
	 * <p>
	 * Updates this view when a triggering condition is met.
	 * </p>
	 * 
	 * @param event The event that occurred to trigger this listener.
	 * 
	 * <dt><b>Conditions:</b>
	 * <dd>PRE:  The model must contain values to be manipulated.</dd>
	 * <dd>POST: The model data is changed and this view is updated.</dd>
	 * </dt>
	 */
	public abstract void actionPerformed(ActionEvent event);
	
	/**
	 * <p>
	 * Generates the slices that will be associated with this pie chart for 
	 * rendering the data.
	 * </p>
	 * 
	 * <dt><b>Conditions:</b>
	 * <dd>PRE:  <code>slices</code> must be initialized and hold a value.</dd>
	 * <dd>POST: New slices are added to <code>slices</code> based on the parse 
	 *           data from this abstract method.</dd>
	 * </dt>
	 */
	public abstract void getSlices();
	
	/**
	 * <p>
	 * Draws the select title based on the values passed for this pie chart.
	 * </p>
	 * 
	 * @param g The Graphics component assigned to this view for painting.
	 * 
	 * <dt><b>Conditions:</b>
	 * <dd>PRE:  None</dd>
	 * <dd>POST: None</dd>
	 * </dt>
	 */
	public abstract void drawTitle(Graphics g);
}	// end class